
#include <linux/kernel.h>


#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/version.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>

#include <linux/uaccess.h>

#define TIMER_CMD_ON _IO('L',3)
#define TIMER_CMD_OFF _IO('L',4)
#define TIMER_CMD_SET _IOW('L',5,int)



struct device_info
{
dev_t dev_num;//设备号

int dev_major;  //主次设备号
int dev_minor;

struct cdev cdev_test;//设备结构体信息

struct class *class;//类和对象
struct device *device;

char kernel_buf[1024];

int counter;
};

struct device_info dev1;

//declare function
static void function_timer(struct timer_list *t);

//init timer
DEFINE_TIMER(test_timer,function_timer);


//timer_function entrance
static void function_timer(struct timer_list *t){
	printk("This is function_timer\n");
//修改定时时间
	mod_timer(&test_timer,jiffies_64+msecs_to_jiffies(dev1.counter));

}


static ssize_t dev_read(struct file* file, char __user *buf, size_t size, loff_t *offset) {
	printk("this is dev_read!\n");
	struct device_info *test_dev = (struct device_info *)file->private_data;

    

	int ret = copy_to_user(buf, test_dev->kernel_buf, strlen(test_dev->kernel_buf));
	if(ret != 0){
		printk("read error!\n");
		return -1;
	}
	return 0;
}
 

static ssize_t dev_write(struct file* file, const char __user *buf, size_t size, loff_t *offset) {
		struct device_info *test_dev = (struct device_info *)file->private_data;
	printk("this is dev_write!\n");
	int ret= copy_from_user(test_dev->kernel_buf, buf, size);
	if(ret != 0){
		printk("write error!\n");
		return -1;
	}
	printk("test_dev->kernel_buf is %s\n",test_dev->kernel_buf);
	return 0;
}
 
/* 打开设备 */
static int dev_open(struct inode* node, struct file* file) {
	file->private_data = &dev1;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	printk("This is dev_open!");
	return 0;
}
 
/* 关闭设备 */
static int dev_close(struct inode* node, struct file* file) {
	del_timer(&test_timer);
	return 0;
}
 

long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg/*可借助地址传参实现数据流的交互*/){

	struct device_info *dev_temp = (struct device_info *)file->private_data;

	if(cmd == TIMER_CMD_ON){
		printk(KERN_EMERG"This is TIMER_CMD_ON \n");
//将定时器加入内核，打开定时器		
		add_timer(&test_timer);

	}else if(cmd == TIMER_CMD_OFF){
		printk(KERN_EMERG"This is TIMER_CMD_OFF \n");	
//关闭定时器
		del_timer(&test_timer);

	}else if(cmd == TIMER_CMD_SET){
		printk(KERN_EMERG"This is TIMER_CMD_SET \n");		
//设置定时器时间
		dev_temp->counter = arg;
		test_timer.expires = jiffies_64 + msecs_to_jiffies(dev_temp->counter);
	}



		return 0;
}



/* 设备操作函数集合结构体 */
static struct file_operations dev_operation = {
	.owner = THIS_MODULE,
	.open = dev_open,
	.read = dev_read,
	.write = dev_write,
	.release = dev_close,
	.unlocked_ioctl = dev_ioctl,
};
 
/* 驱动入口函数 */
static int  hello_init(void) {
	
 
	printk(KERN_EMERG"%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	int ret = alloc_chrdev_region(&dev1.dev_num,0,1,"alloc_name");//动态申请设备号，次设备从0开始，申请一个
	if(ret<0){

		printk("alloc_chrdev_region is error\n");
	}
	printk(KERN_EMERG"alloc_chrdev_region is ok\n");

	dev1.dev_major = MAJOR(dev1.dev_num); 
	dev1.dev_major = MINOR(dev1.dev_num);  

	printk(KERN_EMERG"major is %d\n",dev1.dev_major);
	printk(KERN_EMERG"minot is %d\n",dev1.dev_major);

	dev1.cdev_test.owner = THIS_MODULE;
	cdev_init(&dev1.cdev_test,&dev_operation);
	cdev_add(&dev1.cdev_test,dev1.dev_num,1);

	dev1.class = class_create(THIS_MODULE, "test");
	dev1.device = device_create(dev1.class,NULL,dev1.dev_num,NULL,"test_dev");

	return 0;
	
}
 
/* 驱动出口函数 */
static void  hello_exit(void)	{
	printk(KERN_EMERG"exited!\n");
	del_timer(&test_timer);
	device_destroy(dev1.class, dev1.dev_num);
	class_destroy(dev1.class);
	cdev_del(&dev1.cdev_test);
	unregister_chrdev_region(dev1.dev_num, 1);
	
}
module_init(hello_init);	/*指定设备驱动入口函数*/
module_exit(hello_exit);	/*指定设备驱动出口函数*/
MODULE_LICENSE("GPL");
